using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class OnLifeUpdated : UnityEvent<float>{}


public class Dave : Entity {

    //Speed of moove
    [SerializeField]
    float m_speed = 2.5f;

    float m_lastInputAttackTime;

    List<Ennemy> m_ennemies;

    [SerializeField]
    GameObject m_magicRay;
    
    //Animator Variables
    bool m_idle;
    bool m_running;
    bool m_attack;
    bool m_damaged;
    bool m_dead;
    int m_index;
    int m_combo;
    Power m_power;
    bool m_powerUsed;
    bool m_dabbing;
    bool m_slower;
    bool m_raying;
    bool m_canBeDamaged;

    bool m_usingPower;
    public bool PowerUsed {  set { m_powerUsed = value; } }

    public OnLifeUpdated onLifeUpdated;
    public UnityEvent onPlayerLoose;
    public UnityEvent onRandomBoat;
    public UnityEvent onRandomBoatStop;

    Coroutine lastRandomBoat;

    private void Awake()
    {
        onLifeUpdated = new OnLifeUpdated();
        onPlayerLoose = new UnityEvent();
        onRandomBoat = new UnityEvent();
    }

    protected override void Start()
    {
        base.Start();
        m_ennemies = new List<Ennemy>(FindObjectsOfType<Ennemy>());
        m_team = 0;
        m_canBeDamaged = true;
    }


    Transform getNearestEnnemy()
    {
        if (m_ennemies == null || m_ennemies.Count == 0)
            return null;

        float bestDistance = -1;
        Transform currentNearest = null;

        List<Ennemy> toRemove = new List<Ennemy>();

        foreach(Ennemy e in m_ennemies)
        {
            if(e == null)
            {
                toRemove.Add(e);
                continue;
            }

            if ((currentNearest == null || Vector3.Distance(transform.position, e.transform.position) < bestDistance)
                && e.Activated)
            {
                bestDistance = Vector3.Distance(transform.position, e.transform.position);
                currentNearest = e.transform;
            }
        }

        foreach (Ennemy tr in toRemove)
            m_ennemies.Remove(tr);


        return currentNearest;
  
    }

   

    //Initialization of Dave after players choices
    public void initDave(Caracteristics m_caracs )
    {
        this.m_life = this.m_maxLife = m_caracs.LifeAmount;
        this.m_resistance = m_caracs.Resistance;
        this.m_strenght = m_caracs.Attack;
        m_power = m_caracs.Power;
    }

    protected override void initAnimator()
    {
        m_idle = false;
        m_running = false;
        m_attack = false;
        m_damaged = false;
        m_dead = false;       
    }

    public override void takeDamages(int damages)
    {
        if (m_usingPower || !m_canBeDamaged)
            return;

        base.takeDamages(damages);

        float percentLiferemaining = ((float)m_life / (float)m_maxLife)*100;
        onLifeUpdated.Invoke(percentLiferemaining);

        if(!m_dabbing)
            m_damaged = true;

        m_canBeDamaged = false;

        StartCoroutine(waitAndVeingDamadeable());
    }

    protected override void defeated()
    {
        base.defeated();
        onPlayerLoose.Invoke();
    }

    public void fullLife()
    {
        m_life = m_maxLife;
        onLifeUpdated.Invoke(100);
    }

    protected override void linkingAnimator()
    {
        m_anim.SetBool("Idle", m_idle);
        m_anim.SetBool("Running", m_running);
        m_anim.SetInteger("Combo", m_combo);
        m_anim.SetInteger("index", m_index);


        if(m_attack)
            m_anim.SetTrigger("Attack");

        if (m_damaged)
            m_anim.SetTrigger("Damaged");

        if (m_dead)
            m_anim.SetTrigger("Dead");
    }


    IEnumerator waitAndVeingDamadeable()
    {
        yield return new WaitForSeconds(1.5f);
        m_canBeDamaged = true;
    }

    public void activeMagicRay()
    {
        m_magicRay.SetActive(true);
        StartCoroutine(waitAndEndMagicRay());
    }

    IEnumerator waitAndEndMagicRay()
    {
        yield return new WaitForSeconds(1.5f);
        m_raying = false;
        m_magicRay.SetActive(false);
        m_usingPower = false;
        m_anim.SetBool("Idle", true);
        if(!GameManager.m_currentRoomManager.Clear)
            RandomBoat();

        
    }

    void RandomBoat()
    {
        onRandomBoat.Invoke();
        lastRandomBoat = StartCoroutine(waitAndRandomBoat());
    }

    IEnumerator waitAndRandomBoat()
    {
        yield return new WaitForSeconds(10);
        RandomBoat();
    }

    void usePower()
    {
        m_usingPower = true;
        m_powerUsed = true;

        switch(m_power)
        {
            case Power.Heal:
                m_life = m_maxLife;
                onLifeUpdated.Invoke(100);
                m_slower = true;
                m_anim.speed = 0.5f;
                m_usingPower = false;
                break;
            case Power.MagicRay:
                m_anim.SetTrigger("Ray");
                m_raying = true;
                break;
            case Power.Shockwave:
                m_anim.SetTrigger("Shockwave");
                break;
            default: break;
        }

    }

    public void endShockwave()
    {
        m_usingPower = false;
        m_dabbing = true;
        StartCoroutine(WaitAndStopDabbing());
    }

    IEnumerator WaitAndStopDabbing()
    {
        yield return new WaitForSeconds(10);
        m_anim.SetBool("Idle", true);
        m_dabbing = false;
    }


    public void endSideEffect()
    {
        if (!m_powerUsed)
            return;

        m_powerUsed = false;

        switch (m_power)
        {
            case Power.Heal:
                m_anim.speed = 1;
                m_slower = false;
                break;
            case Power.MagicRay:
                if (lastRandomBoat != null)
                    StopCoroutine(lastRandomBoat);

                onRandomBoatStop.Invoke();
                break;
            default: break;
        }
    }


    void InputManager()
    {

        if (!m_active || m_dabbing)
            return;

        m_idle = false;

        if(m_raying)
        {
            m_moveDirection.x = Input.GetAxis("Horizontal");
            m_moveDirection.z = Input.GetAxis("Vertical");
            transform.forward = m_moveDirection;
            m_moveDirection = Vector3.zero;
            return;
        }


        if (m_combo != 0 && Time.time - m_lastInputAttackTime > 0.5f)
            m_combo = 0;

        m_moveDirection.x = Input.GetAxis("Horizontal");
        m_moveDirection.z = Input.GetAxis("Vertical");


        if(Input.GetButtonDown("Fire2") && !m_powerUsed)
        {
            usePower();
            return;
        }

        if (m_moveDirection.x != 0 || m_moveDirection.z != 0)
        {
            transform.forward = m_moveDirection;
            m_running = true;

            if (Input.GetButtonDown("Fire1"))
            {
                m_attack = true;
                Transform nearestEnnemy = getNearestEnnemy();
                if (nearestEnnemy != null)
                {
                    transform.LookAt(nearestEnnemy);
                    transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, transform.eulerAngles.z);
                }

            }

        }
        else
        {
            if (Input.GetButtonDown("Fire1"))
            {
                m_attack = true;

                if (m_combo == 0)
                {
                    m_combo = 1;
                    m_index = m_index == 0 ? 1 : 0;
                }
                else if (m_combo < 3)
                    m_combo++;
                else
                    m_combo = 0;

                m_lastInputAttackTime = Time.time;

                Transform nearestEnnemy = getNearestEnnemy();
                if (nearestEnnemy != null)
                {
                    transform.LookAt(nearestEnnemy);
                    transform.eulerAngles = new Vector3(0, transform.eulerAngles.y, transform.eulerAngles.z);
                }
            }
            else
                m_idle = true;
        }

    }

    // Update is called once per frame
    void Update ()
    {
        if (!m_active)
            return;

        initAnimator();
        InputManager();
	}

    private void LateUpdate()
    {
        if (!m_active)
            return;

        if (m_damaged)
        {
            m_attack = false;
            m_running = false;
            m_moveDirection = Vector3.zero;
        }


        // m_moveDirection.y = Physics.gravity.y;
        float finalSpeed = m_slower ? m_speed / 2 : m_speed;
        m_controller.Move(m_moveDirection * m_speed * Time.deltaTime);

        if (transform.position.y != 0)
            transform.position = new Vector3(transform.position.x, 0, transform.position.z);

        linkingAnimator();
    }
}
